<!--
 * @Author: zhuxiaoyi
 * @Date: 2024-01-10 18:37:27
 * @LastEditor: zhuxiaoyi
 * @LastEditTime: 2025-03-05 12:10:19
 * @Description: 
-->

<template>
    <el-row>
        <el-col :span="24" style="padding: 20px">
            <el-row>
                <el-col :span="6" :style="`padding-right: 10px;`">
                    <el-card>
                        <el-row>
                            <el-col :span="24"
                                style=" display:flex; justify-content: space-between; margin-bottom: 20px;">
                                <el-input size="small" placeholder="算法查询" :prefix-icon="Search"
                                    style="width: calc(100% - 55px);" v-model="keyword"></el-input>
                                <el-button size="small" type="primary" @click="getAlgorithm">搜索</el-button>
                            </el-col>
                            <el-col :span="24">
                                <span>算法类型</span>&nbsp;
                                <el-tree-select v-model="currentType" :data="treeData" :props="defaultProps"
                                    default-expand-all :render-after-expand="false" :expand-on-click-node="false"
                                    style="width: calc(100% - 70px);"  check-strictly clearable @clear="getAlgorithm" @node-click="handleNodeClick" />
                                <el-divider />
                            </el-col>
                        </el-row>
                        <el-table size="small" :data="tableData" style="width: 100%" :height="view.height - 425">
                            <el-table-column :align="''" prop="identifier" label="算法标识">
                                <template #header>
                                    <div style="display:flex; align-items:center">
                                        <el-icon>
                                            <InfoFilled />
                                        </el-icon>
                                        &nbsp;&nbsp;
                                        <span>算法标识</span>
                                    </div>
                                </template>
                                <template #default="scope">
                                    <el-tag size="small" type="primary" style="cursor: pointer;">
                                        <span @mousedown="startDrag" :nid="scope.row.id"
                                            :label="scope.row.name + '_' + scope.row.identifier">{{ scope.row.name }}_{{
                                                scope.row.identifier }}</span>
                                    </el-tag>
                                </template>
                            </el-table-column>
                            <el-table-column :align="'center'" prop="version" label="版本" width="60">
                                <template #default="scope">
                                    <el-link size="small"> {{
                                        scope.row.version
                                    }}</el-link>
                                </template>
                            </el-table-column>
                        </el-table>
                        <template #footer>
                              <div>
                                <pagination-com :pagination="algorithmPagination"
                                    @handleSizeChange="algorithmSizeChangeHanlder"
                                    @handleCurrentChange="algorithmIndexChangeHanlder"></pagination-com>
                            </div>
                        </template>
                    </el-card>
                </el-col>
                <el-col :span="18">
                    <el-card class="graph-container" :style="`height:${view.height - 195}px; box-sizing: border-box`">
                        <el-row class="graph-head">
                            <el-col :span="24">
                                <el-page-header style="margin-bottom: 10px;" @back="goBack">
                                    <template #content>
                                        <p v-if="nameStatus" style="display:flex;align-items:center">
                                            <span style="margin:0 10px 0 0;font-size: 12px;"> {{ currentGraph.name }}
                                            </span>
                                            <el-icon @click="nameStatus = false" color="#409EFF"
                                                style="cursor: pointer;">
                                                <EditPen />
                                            </el-icon>
                                        </p>
                                        <p style="display:flex;align-items:center" v-if="!nameStatus">
                                            <el-input size="small" v-model="currentGraph.name" style="width: 250px;"
                                                @keyup.enter="nameStatus = true"></el-input>&nbsp;
                                            <el-button size="small" type="success" :icon="Check"
                                                @click="nameStatus = true"></el-button>
                                        </p>
                                    </template>
                                    <template #extra>
                                        <div class="flex items-center">
                                            <el-button type="primary" size="small" @click="addProcess"
                                                :icon="FolderChecked"
                                                v-if="route.params.id == 'newGraph'">新增流程</el-button>
                                            <el-button type="primary" v-if="route.params.id !== 'newGraph'" size="small"
                                                @click="updateProcess" :icon="FolderChecked">保存流程</el-button>
                                        </div>
                                    </template>
                                </el-page-header>
                            </el-col>
                        </el-row>
                        <div id="container" :style="`height:${view.height - 255}px;`"></div>
                        <div id="mini-container"></div>
                        <TeleportContainer />
                    </el-card>
                </el-col>
            </el-row>
        </el-col>
    </el-row>
</template>
<script setup lang="ts">
import { defineComponent, reactive, ref, toRefs, onMounted, watch ,nextTick} from "vue";
import paginationCom from "@/components/pagination/paginationCom.vue";
// import * as _ from "lodash";
import { ElMessage, ElMessageBox } from "element-plus";
import axios from "axios";
import { Graph, Path, Cell, Edge, } from '@antv/x6'
import { Dnd } from "@antv/x6-plugin-dnd";
import { Selection } from "@antv/x6-plugin-selection";
import ProgressNode from "@/components/ProgressNode/ProgressNode.vue";
import { register, getTeleport } from "@antv/x6-vue-shape";
import { MiniMap } from '@antv/x6-plugin-minimap'
import HttpService from "@/api/api";
import { Search, CaretRight, InfoFilled, Edit, ArrowLeft, VideoPlay, FolderChecked, Check } from "@element-plus/icons-vue";
import { useRoute, useRouter } from "vue-router";
import { Scroller } from "@antv/x6-plugin-scroller";

const router = useRouter()
const route = useRoute()
const currentType = ref()
const treeData = ref([])
var graph, dnd;
let tableData = ref([])
let tableLoading = ref(false)
let keyword = ref('')
let nameStatus = ref(true)
const currentGraph = reactive({
    id: "",
    name: "",
    graph: "",
    flow: ""
})

const defaultProps = {
    children: 'children',
    label: 'name',
    value: 'id'
}

const image = {
    logo: "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*evDjT5vjkX0AAAAAAAAAAAAAARQnAQ",
    success:
        "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*6l60T6h8TTQAAAAAAAAAAAAAARQnAQ",
    failed:
        "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SEISQ6My-HoAAAAAAAAAAAAAARQnAQ",
    running:
        "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*t8fURKfgSOgAAAAAAAAAAAAAARQnAQ",
};

const TeleportContainer = getTeleport();

register({
    shape: "custom-vue-node",
    width: 220,
    height: 56,
    component: ProgressNode,
    ports: {
        groups: {
            circle: {
                position: {
                    name: 'ellipseSpread',
                    args: {
                        compensateRotate: true,
                    },
                },
                attrs: {
                    circle: {
                        magnet: true,
                        stroke: "#8f8f8f",
                        r: 5,
                    },
                },
            },
        },
    },
});


let algorithmPagination = reactive({
    page_index: 1,
    page_size: 50,
    page_total: 0,
});

const getTree = function () {
    let params = {};
    treeData.value.length = 0
    HttpService.AlgorithmTypeManage.getTree(
        params,
        (res) => {
            setTimeout(() => {
                if (res.status == 200) {
                    let results = res.data.data
                    results.forEach(result => {
                        treeData.value.push(result)
                    })

                } else {
                    ElMessage({
                        message: res,
                        type: "error",
                    });
                }
            }, 300)
        },
        (error) => {
            console.log(error);
        }
    )
}
getTree()

onMounted(() => {
    let container = document.getElementById("container");
    graph = new Graph({
        container: container,
        panning: {
            enabled: true,
            eventTypes: ["leftMouseDown"],
        },
        mousewheel: {
            enabled: true,
            modifiers: ["ctrl", "meta"],
        },
        background: {
            color: "#F2F7FA",
        },
        grid: {
            size: 10,
            visible: true,
            type: "doubleMesh",
            args: [
                {
                    color: "#eee", // 主网格线颜色
                    thickness: 1, // 主网格线宽度
                },
                {
                    color: "#ddd", // 次网格线颜色
                    thickness: 1, // 次网格线宽度
                    factor: 4, // 主次网格线间隔
                },
            ],
        },

    });

    graph.use(
        new Selection({
            multiple: true,
            rubberEdge: true,
            rubberNode: true,
            modifiers: "shift",
            rubberband: true,
        })
    );

    dnd = new Dnd({
        target: graph,
    });

    graph.use(
        new Scroller({
            enabled: true,
            pageVisible: true,
            pageBreak: true,
            pannable: true,
        })
    );

    graph.use(
        new MiniMap({
            container: document.getElementById('mini-container'),
            width: 200,
            height: 160,
            padding: 10,
        }),
    )
    const showPorts = (ports: NodeListOf<SVGElement>, show: boolean) => {
        for (let i = 0, len = ports.length; i < len; i += 1) {
            ports[i].style.visibility = show ? "visible" : "hidden";
        }
    };
    graph.on("node:mouseenter", () => {
        const ports = container.querySelectorAll(
            ".x6-port-body"
        ) as NodeListOf<SVGElement>;
        showPorts(ports, true);
    });
    graph.on("node:mouseleave", () => {
        const ports = container.querySelectorAll(
            ".x6-port-body"
        ) as NodeListOf<SVGElement>;
        showPorts(ports, false);
    });
    graph.on("cell:mouseenter", ({ cell }) => {
        if (cell.isNode()) {
            cell.addTools([
                {
                    name: "boundary",
                    args: {
                        attrs: {
                            stroke: "#333",
                            "stroke-width": 0.5,
                            "fill-opacity": 0.2,
                        },
                    },
                },
                {
                    name: "button-remove",
                    args: {
                        x: 0,
                        y: 0,
                        offset: { x: 216, y: 0 },
                    },
                },
            ]);
        } else {
            cell.addTools(["button-remove"]);
        }
    });

    graph.on("cell:mouseleave", ({ cell }) => {
        cell.removeTools();
    });

    getAlgorithm()
    initGraph()

});

const getAlgorithm = function () {
    let params = {
        page_size: algorithmPagination.page_size,
        page_index: algorithmPagination.page_index,
        keyword: keyword.value,
        type: currentType.value
    };
    tableData.value.length = 0;
    tableLoading.value = true
    HttpService.algorithmManage.getAlgorithms(
        params,
        (res) => {

            if (res.status == 200) {
                res.data.data.map((item, index) => {
                    tableData.value.push(item);
                    tableLoading.value = false
                });
                algorithmPagination.page_total = res.data.total
            } else {
                console.log("获取信息失败" + res);
                tableLoading.value = false
            }
        },
        (error) => {
            console.log(error);

            tableLoading.value = false
        }
    );
};

const algorithmSizeChangeHanlder = function (page_size: number) {
    algorithmPagination.page_size = page_size;
    getAlgorithm();
};
const algorithmIndexChangeHanlder = function (page_index: number) {
    algorithmPagination.page_index = page_index;
    getAlgorithm();
};





var view = reactive({
    height: window.innerHeight,
});

const startDrag = (e) => {
    let id = e.target.getAttribute("nid");
    let label = e.target.getAttribute("label");
    let  algorithm
    let color= e.target.getAttribute("color");
    let icon= e.target.getAttribute("icon");
    let des= e.target.getAttribute("des");
    let pause= e.target.getAttribute("pause");
    let identifier= e.target.getAttribute("identifier");
    const node = graph.createNode({
        id: id,
        shape: 'custom-vue-node',
        data: {
            id,
            label,
            status: "pennding",
            progress: 0,
            des,
            pause,
            identifier
        },
    });

    let positions = ['top', 'bottom','left','right']
    positions.forEach((position, index) => {
        node.addPort({
            id: `port_${index}`,
            group: 'circle',
        })
    })
    dnd.start(node, e);
};


const handleDownload = function (content, name) {
    var eleLink = document.createElement("a");
    eleLink.download = name + ".json";
    eleLink.style.display = "none";
    var jsonContent = JSON.stringify(content, undefined, 4);
    var blob = new Blob([jsonContent], { type: "text/json" });
    eleLink.href = URL.createObjectURL(blob);
    document.body.appendChild(eleLink);
    eleLink.click();
    document.body.removeChild(eleLink);
};

const saveGraph = function () {
    handleDownload(graph.toJSON(), "自定义图谱");
};


const getProcess = function (id) {
    let params = {
        id
    };
    HttpService.processListManage.getProcess(
        params,
        (res) => {

            if (res.status == 200) {
                let graph = res.data.data
                Object.assign(currentGraph, graph)
                createGraphNode()
            } else {
                console.log("获取信息失败" + res);
            }
        },
        (error) => {
            console.log(error);
        }
    );
}

const initGraph = async function () {
    let graphId = route.params.id
    if (graphId != 'newGraph' && graphId != undefined) {
        getProcess(graphId)
    } else {
        currentGraph.name = '未命名_算法流程_' + new Date().getTime()
    }
}

const createGraphNode = function () {
    graph.fromJSON(JSON.parse(currentGraph.graph))
}

const goBack = function () {
    router.push('/index/general/processManage/processList')
}

const addProcess = function () {
    let params = {
        name: currentGraph.name,
        graph: JSON.stringify(graph.toJSON())
    };
    HttpService.processListManage.addProcess(
        params,
        (res) => {

            if (res.status == 200) {
                ElMessage({
                    message: res.data.message,
                    type: 'success',
                })
                currentGraph.id = res.data.data.id
                enterToGraph(currentGraph)
            } else {
                console.log("图谱保存失败" + res);
            }
        },
        (error) => {
            console.log(error);
        }
    );
}

const updateProcess = function () {
    let params = {
        id: route.params.id,
        name: currentGraph.name,
        graph: JSON.stringify(graph.toJSON())
    };
    HttpService.processListManage.updateProcess(
        params,
        (res) => {
            if (res.status == 200) {
                ElMessage({
                    message: res.data.message,
                    type: 'success',
                })
                currentGraph.id = res.data.data.id
                enterToGraph(currentGraph)
            } else {
                console.log("图谱保存失败" + res);
            }
        },
        (error) => {
            console.log(error);
        }
    );
}


const enterToGraph = function (process) {
    router.push('/index/general/processManage/processGraph/' + process.id)
}

const handleNodeClick = function (type, node) {
    // if (node.isLeaf) {
        nextTick(() => {
            getAlgorithm()
        })
    // }
}

/* window.onresize = _.debounce(() => {
    view.height = window.innerHeight;
}, 100); */

</script>
<style lang="scss" scoped>
#container {
    height: 600px;
}
</style>
<style lang="scss">
.x6-node-selected .pennding {
    border-color: #1890ff;
    border-radius: 2px;
    box-shadow: 0 0 0 4px #d4e8fe;
}

.x6-node-selected .running {
    border-color: #E6A23C;
    border-radius: 2px;
    box-shadow: 0 0 0 4px #e6d4ba;
}

.x6-node-selected .success {
    border-color: #52c41a;
    border-radius: 2px;
    box-shadow: 0 0 0 4px #ccecc0;
}

.x6-node-selected .failed {
    border-color: #ff4d4f;
    border-radius: 2px;
    box-shadow: 0 0 0 4px #fedcdc;
}
.x6-node-selected .pause {
    border-color: #CBAEFF;
    border-radius: 2px;
    box-shadow: 0 0 0 4px rgba(254, 220, 220, 0.5);
}

.graph-head {
    .el-page-header__back {
        color: #fff;
    }
}

.graph-container {
    position: relative;

    .el-card__body {
        padding: 15px;
    }

    #mini-container {
        position: absolute;
        bottom: 10px;
    }

}
</style>
